1 package org.apache.lucene.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import java.util.Arrays;
21 import java.util.List;
22
23 import static org.apache.lucene.util.RamUsageEstimator.NUM_BYTES_OBJECT_REF;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public final class ByteBlockPool {
45 public final static int BYTE_BLOCK_SHIFT = 15;
46 public final static int BYTE_BLOCK_SIZE = 1 << BYTE_BLOCK_SHIFT;
47 public final static int BYTE_BLOCK_MASK = BYTE_BLOCK_SIZE - 1;
48
49
50
51 public abstract static class Allocator {
52 protected final int blockSize;
53
54 public Allocator(int blockSize) {
55 this.blockSize = blockSize;
56 }
57
58 public abstract void recycleByteBlocks(byte[][] blocks, int start, int end);
59
60 public void recycleByteBlocks(List<byte[]> blocks) {
61 final byte[][] b = blocks.toArray(new byte[blocks.size()][]);
62 recycleByteBlocks(b, 0, b.length);
63 }
64
65 public byte[] getByteBlock() {
66 return new byte[blockSize];
67 }
68 }
69
70
71 public static final class DirectAllocator extends Allocator {
72
73 public DirectAllocator() {
74 this(BYTE_BLOCK_SIZE);
75 }
76
77 public DirectAllocator(int blockSize) {
78 super(blockSize);
79 }
80
81 @Override
82 public void recycleByteBlocks(byte[][] blocks, int start, int end) {
83 }
84 }
85
86
87
88 public static class DirectTrackingAllocator extends Allocator {
89 private final Counter bytesUsed;
90
91 public DirectTrackingAllocator(Counter bytesUsed) {
92 this(BYTE_BLOCK_SIZE, bytesUsed);
93 }
94
95 public DirectTrackingAllocator(int blockSize, Counter bytesUsed) {
96 super(blockSize);
97 this.bytesUsed = bytesUsed;
98 }
99
100 @Override
101 public byte[] getByteBlock() {
102 bytesUsed.addAndGet(blockSize);
103 return new byte[blockSize];
104 }
105
106 @Override
107 public void recycleByteBlocks(byte[][] blocks, int start, int end) {
108 bytesUsed.addAndGet(-((end-start)* blockSize));
109 for (int i = start; i < end; i++) {
110 blocks[i] = null;
111 }
112 }
113 };
114
115
116
117
118
119 public byte[][] buffers = new byte[10][];
120
121
122 private int bufferUpto = -1;
123
124 public int byteUpto = BYTE_BLOCK_SIZE;
125
126
127 public byte[] buffer;
128
129 public int byteOffset = -BYTE_BLOCK_SIZE;
130
131 private final Allocator allocator;
132
133 public ByteBlockPool(Allocator allocator) {
134 this.allocator = allocator;
135 }
136
137
138
139
140
141
142
143 public void reset() {
144 reset(true, true);
145 }
146
147
148
149
150
151
152
153
154
155
156 public void reset(boolean zeroFillBuffers, boolean reuseFirst) {
157 if (bufferUpto != -1) {
158
159
160 if (zeroFillBuffers) {
161 for(int i=0;i<bufferUpto;i++) {
162
163 Arrays.fill(buffers[i], (byte) 0);
164 }
165
166 Arrays.fill(buffers[bufferUpto], 0, byteUpto, (byte) 0);
167 }
168
169 if (bufferUpto > 0 || !reuseFirst) {
170 final int offset = reuseFirst ? 1 : 0;
171
172 allocator.recycleByteBlocks(buffers, offset, 1+bufferUpto);
173 Arrays.fill(buffers, offset, 1+bufferUpto, null);
174 }
175 if (reuseFirst) {
176
177 bufferUpto = 0;
178 byteUpto = 0;
179 byteOffset = 0;
180 buffer = buffers[0];
181 } else {
182 bufferUpto = -1;
183 byteUpto = BYTE_BLOCK_SIZE;
184 byteOffset = -BYTE_BLOCK_SIZE;
185 buffer = null;
186 }
187 }
188 }
189
190
191
192
193
194
195 public void nextBuffer() {
196 if (1+bufferUpto == buffers.length) {
197 byte[][] newBuffers = new byte[ArrayUtil.oversize(buffers.length+1,
198 NUM_BYTES_OBJECT_REF)][];
199 System.arraycopy(buffers, 0, newBuffers, 0, buffers.length);
200 buffers = newBuffers;
201 }
202 buffer = buffers[1+bufferUpto] = allocator.getByteBlock();
203 bufferUpto++;
204
205 byteUpto = 0;
206 byteOffset += BYTE_BLOCK_SIZE;
207 }
208
209
210
211
212
213 public int newSlice(final int size) {
214 if (byteUpto > BYTE_BLOCK_SIZE-size)
215 nextBuffer();
216 final int upto = byteUpto;
217 byteUpto += size;
218 buffer[byteUpto-1] = 16;
219 return upto;
220 }
221
222
223
224
225
226
227
228
229
230
231
232 public final static int[] NEXT_LEVEL_ARRAY = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9};
233
234
235
236
237 public final static int[] LEVEL_SIZE_ARRAY = {5, 14, 20, 30, 40, 40, 80, 80, 120, 200};
238
239
240
241
242
243 public final static int FIRST_LEVEL_SIZE = LEVEL_SIZE_ARRAY[0];
244
245
246
247
248
249 public int allocSlice(final byte[] slice, final int upto) {
250
251 final int level = slice[upto] & 15;
252 final int newLevel = NEXT_LEVEL_ARRAY[level];
253 final int newSize = LEVEL_SIZE_ARRAY[newLevel];
254
255
256 if (byteUpto > BYTE_BLOCK_SIZE-newSize) {
257 nextBuffer();
258 }
259
260 final int newUpto = byteUpto;
261 final int offset = newUpto + byteOffset;
262 byteUpto += newSize;
263
264
265
266 buffer[newUpto] = slice[upto-3];
267 buffer[newUpto+1] = slice[upto-2];
268 buffer[newUpto+2] = slice[upto-1];
269
270
271 slice[upto-3] = (byte) (offset >>> 24);
272 slice[upto-2] = (byte) (offset >>> 16);
273 slice[upto-1] = (byte) (offset >>> 8);
274 slice[upto] = (byte) offset;
275
276
277 buffer[byteUpto-1] = (byte) (16|newLevel);
278
279 return newUpto+3;
280 }
281
282
283
284 public void setBytesRef(BytesRef term, int textStart) {
285 final byte[] bytes = term.bytes = buffers[textStart >> BYTE_BLOCK_SHIFT];
286 int pos = textStart & BYTE_BLOCK_MASK;
287 if ((bytes[pos] & 0x80) == 0) {
288
289 term.length = bytes[pos];
290 term.offset = pos+1;
291 } else {
292
293 term.length = (bytes[pos]&0x7f) + ((bytes[pos+1]&0xff)<<7);
294 term.offset = pos+2;
295 }
296 assert term.length >= 0;
297 }
298
299
300
301
302
303 public void append(final BytesRef bytes) {
304 int length = bytes.length;
305 if (length == 0) {
306 return;
307 }
308 int offset = bytes.offset;
309 int overflow = (length + byteUpto) - BYTE_BLOCK_SIZE;
310 do {
311 if (overflow <= 0) {
312 System.arraycopy(bytes.bytes, offset, buffer, byteUpto, length);
313 byteUpto += length;
314 break;
315 } else {
316 final int bytesToCopy = length-overflow;
317 if (bytesToCopy > 0) {
318 System.arraycopy(bytes.bytes, offset, buffer, byteUpto, bytesToCopy);
319 offset += bytesToCopy;
320 length -= bytesToCopy;
321 }
322 nextBuffer();
323 overflow = overflow - BYTE_BLOCK_SIZE;
324 }
325 } while(true);
326 }
327
328
329
330
331
332
333 public void readBytes(final long offset, final byte bytes[], final int off, final int length) {
334 if (length == 0) {
335 return;
336 }
337 int bytesOffset = off;
338 int bytesLength = length;
339 int bufferIndex = (int) (offset >> BYTE_BLOCK_SHIFT);
340 byte[] buffer = buffers[bufferIndex];
341 int pos = (int) (offset & BYTE_BLOCK_MASK);
342 int overflow = (pos + length) - BYTE_BLOCK_SIZE;
343 do {
344 if (overflow <= 0) {
345 System.arraycopy(buffer, pos, bytes, bytesOffset, bytesLength);
346 break;
347 } else {
348 final int bytesToCopy = length - overflow;
349 System.arraycopy(buffer, pos, bytes, bytesOffset, bytesToCopy);
350 pos = 0;
351 bytesLength -= bytesToCopy;
352 bytesOffset += bytesToCopy;
353 buffer = buffers[++bufferIndex];
354 overflow = overflow - BYTE_BLOCK_SIZE;
355 }
356 } while (true);
357 }
358 }
359